#ifndef ATOMIC_H
#define ATOMIC_H

#if defined(AE_NO_THREAD)
#define memory_barrier()
#elif defined(__GNUC__)
#define memory_barrier() __sync_synchronize()
#elif defined(_MSC_VER)
#define memory_barrier() MemoryBarrier()
#endif

#ifndef __BIT64__
typedef long __atomic_type;
#else
typedef long long __atomic_type;
#endif
typedef volatile __atomic_type* __atomic_ptr;
typedef struct { __atomic_type counter; } atomic_t;

#define ATOMIC_INIT(i)	{ (i) }

static inline __atomic_type atomic_read(atomic_t *v)
{
	memory_barrier();
	return *(__atomic_ptr)&v->counter;
}

static inline void atomic_set(atomic_t *v, __atomic_type i)
{
	v->counter = i;
	memory_barrier();
}

static inline __atomic_type atomic_inc_return(atomic_t *v)
{
#if defined(AE_NO_THREAD)
	return ++ v->counter;
#elif defined(__GNUC__)
	return __sync_add_and_fetch((__atomic_ptr)&v->counter, 1);
#elif defined(_MSC_VER)
#ifndef __BIT64__
	return InterlockedIncrement((__atomic_ptr)&v->counter);
#else
	return InterlockedIncrement64((__atomic_ptr)&v->counter);
#endif
#endif
}

static inline __atomic_type atomic_dec_return(atomic_t *v)
{
#if defined(AE_NO_THREAD)
	return -- v->counter;
#elif defined(__GNUC__)
	return __sync_sub_and_fetch((__atomic_ptr)&v->counter, 1);
#elif defined(_MSC_VER)
#ifndef __BIT64__
	return InterlockedDecrement((__atomic_ptr)&v->counter);
#else
	return InterlockedDecrement64((__atomic_ptr)&v->counter);
#endif
#endif
}

static inline void atomic_inc(atomic_t *v)
{
	atomic_inc_return(v);
}

static inline void atomic_dec(atomic_t *v)
{
	atomic_dec_return(v);
}

#define atomic_dec_and_test(v)		(atomic_dec_return(v) == 0)
#define atomic_inc_and_test(v)		(atomic_inc_return(v) == 0)

static inline __atomic_type atomic_cmpxchg(atomic_t *v, __atomic_type o, __atomic_type n)
{
#if defined(AE_NO_THREAD)
	__atomic_type t = v->counter;
	if(t == o)
		v->counter = n;
	return t;
#elif defined(__GNUC__)
	return __sync_val_compare_and_swap ((__atomic_ptr)&v->counter, o, n);
#elif defined(_MSC_VER)
#ifndef __BIT64__
	return InterlockedCompareExchange((__atomic_ptr)&v->counter, n, o);
#else
	return InterlockedCompareExchange64((__atomic_ptr)&v->counter, n, o);
#endif
#endif
}

#endif
